#!/usr/bin/env node
/**
 * Nginx自动化IP封禁系统 - Node.js实现
 * 专为Windows环境设计，替代PowerShell方案
 * 版本: 2.0
 */

const nginx_path = `D:\\Soft\\Nginx`// nginx目录

// 配置区域 - 根据您的环境调整
const config = {
    logPath: `${nginx_path}\\logs\\access.log`,  // Nginx访问日志路径
    blocklistFile: `${nginx_path}\\conf\\blocklist.conf`,  // Nginx黑名单文件
    nginxPath: `${nginx_path}\\nginx.exe`,  // Nginx可执行文件路径
    threshold: 50,  // 每5分钟请求阈值
    blockDuration: 3600,  // 封禁时间(秒)
    debug: true,  // 调试模式
    firewallRulePrefix: 'NODEJS_BLOCK_',  // 防火墙规则前缀
    blockIPWithFirewall: false,  // 是否使用防火墙封禁IP
};

// 导入依赖
const fs = require('fs-extra');
const path = require('path');
const { execSync } = require('child_process');
const moment = require('moment');
const winston = require('winston');

// 配置日志
const logger = winston.createLogger({
    level: 'info',
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.printf(info => `[${info.timestamp}] ${info.level}: ${info.message}`)
    ),
    transports: [
        new winston.transports.Console(),
        new winston.transports.File({
            filename: `${nginx_path}\\logs\\block-attackers.log`,
            maxsize: 5242880, // 5MB
            maxFiles: 5
        })
    ]
});

/**
 * 检查IP是否为有效IPv4地址
 * @param {string} ip - 要检查的IP地址
 * @returns {boolean} 是否为有效IPv4
 */
function isValidIPv4(ip) {
    const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
    return ipv4Regex.test(ip);
}

/**
 * 添加Windows防火墙规则封禁IP
 * @param {string} ip - 要封禁的IP地址
 * @param {number} count - 请求次数
 * @returns {boolean} 是否成功
 */
function blockIPWithFirewall(ip, count) {
    try {
        const ruleName = `${config.firewallRulePrefix}${ip.replace(/\./g, '_')}`;
        const command = `netsh advfirewall firewall add rule name="${ruleName}" dir=in action=block remoteip=${ip} protocol=TCP localport=80,443 profile=any`;

        logger.info(`执行防火墙命令: ${command}`);
        execSync(command, { stdio: 'pipe' });

        logger.info(`已通过防火墙封禁IP: ${ip} (请求量: ${count})`);
        return true;
    } catch (error) {
        logger.error(`防火墙封禁IP ${ip} 失败: ${error.message}`);
        return false;
    }
}

/**
 * 检查IP是否已被防火墙封禁
 * @param {string} ip - 要检查的IP地址
 * @returns {boolean} 是否已被封禁
 */
function isIPBlockedByFirewall(ip) {
    try {
        const ruleName = `${config.firewallRulePrefix}${ip.replace(/\./g, '_')}`;
        const command = `netsh advfirewall firewall show rule name="${ruleName}"`;
        const output = execSync(command, { stdio: 'pipe' }).toString();

        return output.includes('No rules match the specified criteria.');
    } catch (error) {
        return false;
    }
}
/**
 * 更新Nginx黑名单文件
 * @param {string} ip - 要添加到黑名单的IP
 */
function updateNginxBlocklist(ip) {
    try {
        let blocklist = fs.existsSync(config.blocklistFile)
            ? fs.readFileSync(config.blocklistFile, 'utf8')
            : '### 自动封禁IP列表 - Nginx Anti-DDoS\n';

        // 检查IP是否已在黑名单中
        if (!blocklist.includes(`deny ${ip};`)) {
            blocklist += `\ndeny ${ip}; # 自动封禁 (${moment().format('YYYY-MM-DD HH:mm:ss')})`;
            fs.writeFileSync(config.blocklistFile, blocklist, 'utf8');
            logger.info(`已添加IP到Nginx黑名单: ${ip}`);

            // 重新加载Nginx
            try {
                execSync(`restart.bat`, { stdio: 'inherit', });
                logger.info('Nginx配置已重新加载');
            } catch (error) {
                logger.error(`重新加载Nginx失败: ${error.message}`);
            }
        }
    } catch (error) {
        logger.error(`更新Nginx黑名单失败: ${error.message}`);
    }
}

/**
 * 分析Nginx日志并封禁恶意IP
 */
function analyzeAndBlock() {
    const startTime = moment();
    logger.info('开始执行IP封禁检查...');

    // 检查日志文件是否存在
    if (!fs.existsSync(config.logPath)) {
        logger.error(`错误：Nginx日志文件不存在 - ${config.logPath}`);
        return;
    }

    // 检查blocklist文件是否存在，不存在则创建
    if (!fs.existsSync(config.blocklistFile)) {
        fs.writeFileSync(config.blocklistFile, '### 自动封禁IP列表 - Nginx Anti-DDoS\n', 'utf8');
        logger.info(`已创建Nginx黑名单文件: ${config.blocklistFile}`);
    }

    try {
        // 读取最近5分钟的日志
        const logContent = fs.readFileSync(config.logPath, 'utf8');
        const logLines = logContent.split('\n');
        const fiveMinutesAgo = moment().subtract(5, 'minutes');

        const recentLogs = logLines.filter(line => {
            if (!line.trim()) return false;

            // 提取日志时间戳 (格式: [10/Oct/2023:14:30:22 +0000])
            const timestampMatch = line.match(/\[(\d{2}\/\w{3}\/\d{4}:\d{2}:\d{2}:\d{2})/);
            if (timestampMatch) {
                const logTime = moment(timestampMatch[1], 'DD/MMM/YYYY:HH:mm:ss');
                return logTime.isAfter(fiveMinutesAgo);
            }
            return false;
        });

        // 分析IP请求频率
        const ipCounts = {};
        recentLogs.forEach(line => {
            const ipMatch = line.match(/^(\d+\.\d+\.\d+\.\d+)/);
            if (ipMatch) {
                const ip = ipMatch[1];
                if (isValidIPv4(ip)) {
                    ipCounts[ip] = (ipCounts[ip] || 0) + 1;
                }
            }
        });

        // 识别需要封禁的IP
        let blockedCount = 0;
        Object.entries(ipCounts).forEach(([ip, count]) => {
            if (count > config.threshold) {
                console.log(`封禁IP: ${ip} (请求量: ${count})`);
                config.blockIPWithFirewall && !isIPBlockedByFirewall(ip) && blockIPWithFirewall(ip, count)

                updateNginxBlocklist(ip);
                blockedCount++;
            }
        });

        const executionTime = moment().diff(startTime, 'seconds', true);
        logger.info(`检查完成，共封禁 ${blockedCount} 个IP，耗时 ${executionTime.toFixed(2)} 秒`);

    } catch (error) {
        logger.error(`分析日志时出错: ${error.message}`);
    }
}

/**
 * 清理过期的封禁规则
 */
function cleanupExpiredBlocks() {
    try {
        // 获取所有封禁规则
        const command = `netsh advfirewall firewall show rule name=all`;
        const output = execSync(command, { stdio: 'pipe' }).toString();

        // 提取所有封禁规则
        const ruleNames = [];
        const ruleRegex = /Rule Name:\s+("NODEJS_BLOCK_[^"]+")/g;
        let match;
        while ((match = ruleRegex.exec(output)) !== null) {
            ruleNames.push(match[1].replace(/"/g, ''));
        }

        // 删除过期规则
        let cleanedCount = 0;
        ruleNames.forEach(ruleName => {
            try {
                // 检查规则是否过期（简单实现，实际应记录创建时间）
                // 这里简化处理：直接删除所有规则，由主流程重新添加
                // 实际生产环境应记录规则创建时间
                const deleteCommand = `netsh advfirewall firewall delete rule name="${ruleName}"`;
                execSync(deleteCommand, { stdio: 'pipe' });
                cleanedCount++;
                logger.info(`已清理过期防火墙规则: ${ruleName}`);
            } catch (error) {
                logger.error(`清理规则 ${ruleName} 失败: ${error.message}`);
            }
        });

        if (cleanedCount > 0) {
            logger.info(`清理完成，共移除 ${cleanedCount} 个过期规则`);
        }

    } catch (error) {
        logger.error(`清理过期规则时出错: ${error.message}`);
    }
}

/**
 * 主执行函数
 */
function main() {
    logger.info('===== IP封禁系统启动 =====');

    // 分析并封禁恶意IP
    analyzeAndBlock();

    // 清理过期规则（每小时执行一次，这里简化处理）
    if (moment().minute() < 5) { // 每小时前5分钟执行
        cleanupExpiredBlocks();
    }

    logger.info('===== IP封禁系统执行完毕 =====\n');
}

// 如果直接运行脚本，执行主函数
if (require.main === module) {
    main();
}